#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include "environment.h"
#include "predator.h"
#include "prey.h"
#include "dynamicprogramming.h"
#include "dynamicprogrammingsmart.h"
#include <iomanip>

using namespace std;

int main () {

	// Randomizing number generator
	srand( time( NULL ) );

	int menuSelect, timer;

	cout << setprecision(4) << fixed;

	// Printing introduction
	cout << "\n\nAutonomous Agents Lab - Assignment 1\n";
	cout << "Selection menu:\n\n";

	do {

	// Printing Menu
	cout << "Enter 1 to execute the simulation of the environment ( Ex 1 );\n";
	cout << "Enter 2 to execute Iterative Policy Evaluation ( Ex 2 );\n";
	cout << "Enter 3 to execute Value Iteration ( Ex 4 );\n";
	cout << "Enter 4 to execute Policy Iteration ( Ex 5 );\n";
	cout << "Enter 5 to execute Iterative Policy Evaluation Smart ( Ex 3 );\n";
	cout << "Enter 6 to execute Value Iteration Smart ( Ex 3 );\n";
	cout << "Enter 7 to execute Policy Iteration Smart ( Ex 3 );\n";
	cout << "Enter 0 to exit;\n\n";
	cin >> menuSelect;
	cout << "\n";

	timer = clock();

	switch ( menuSelect ) {
		// EXERCISE 1: SIMULATION OF RANDOM POLICY
		case 1: {
			// Temporary environment, at the next closing bracket every variabile here
			// will be deallocated

			// Loading environment
			Environment env;

			// Creating predators and Preys
			Predator * pred = new Predator(&env);
			Prey * prey = new Prey(&env);

			// Loading actors into the environment
			env.addPredator(pred, 0, 0);
			env.addPrey(prey, 5, 5);

			// Statistical Variables
			int time[100], simNum = 100;
			double avgTime = 0, sigmaTime = 0;

			// Ask if you want mean and sigma for 100 runs or the print for a single run
			int input;
			do {
				cout << "Enter 1 to examine a single simulation\n";
				cout << "Enter 2 to see the mean and variance for 100 simulations\n\n";
				cin >> input;
				cout << "\n";
			} while ( input != 1 && input != 2 );

			if ( input == 1 ) {
				env.setPrint(true);

				cout << "Starting Simulation...\n\n";
				env.startSimulation();
				break;
			}

			cout << "Running Simulations...\n\n";

			// Loop for running multiple simulations
			for ( int i = 0; i < simNum; i++ ) {
				// Number of steps performed
				time[i] = env.startSimulation();
				avgTime += (double) time[i];
			}

			// Calculating average steps performed
			avgTime /= (double) simNum;

			// Calculating variance
			for ( int i = 0; i < simNum; i++ )
				sigmaTime += pow( (double)time[i] - avgTime, 2);

			// Calculating standard deviation
			sigmaTime = sqrt( sigmaTime/simNum );

			// OUTPUT
			cout << "Average time taken by the Predator in " << simNum << " Simulations: " << avgTime << "\n";
			cout << "Standard deviation is " << sigmaTime << "\n";

			// Deallocate the actors before closing the program
			env.deleteAllAgents();

		}	// End of temporary environment
        break;

		// EXERCISE 2: ITERATIVE POLICY EVALUATION
		case 2: {
			DynamicProgramming dynam;

			cout << "Iterations to evaluate all states' policy: "
									<< dynam.policyEvaluation(0.8, false) << "\n\n";
			cout << "Results: \n";
			cout << "Value of state (  0,  0 ) - (  5,  5 ) : "
									<< dynam.getStateValue( 0,  0,  5,  5) << "\n";
			cout << "Value of state (  2,  3 ) - (  5,  4 ) : "
									<< dynam.getStateValue( 2,  3,  5,  4) << "\n";
			cout << "Value of state (  2, 10 ) - ( 10,  0 ) : "
									<< dynam.getStateValue( 2, 10, 10,  0) << "\n";
			cout << "Value of state ( 10, 10 ) - (  0,  0 ) : "
									<< dynam.getStateValue(10, 10,  0,  0) << "\n";
		}	// End of temporary environment
        break;

		//EXERCISE 3: VALUE ITERATION
		case 3: {
            DynamicProgramming dynam;

            for ( double discountFactor=0.1; discountFactor<=0.9; discountFactor+=0.2 ) {
				cout << "For Discount Factor: " << discountFactor << "\n";
                cout << "Cycles of Value Iteration: " << dynam.valueIteration(discountFactor) << "\n";
                cout << "Results: \n\n";

                for ( int i = 0; i < 11; i++ ) {
                    for ( int j = 0; j < 11; j++ )
						cout << dynam.getStateValue(j,i,5,5) << "\t";
					cout << "\n";
				}
				cout << "\n";
			}	// End discount for
        }	// End of case 3
        break;

		//EXERCISE 4: POLICY ITERATION
        case 4: {
			DynamicProgramming dynam;

            for ( double discountFactor=0.1; discountFactor<=0.9; discountFactor+=0.2 ) {
				cout << "For Discount Factor: " << discountFactor << "\n";
                cout << "Cycles of Policy Iteration: " << dynam.policyIteration(discountFactor) << "\n";
                cout << "Results: \n\n";

				for ( int i = 10; i >= 0; i-- ) {
					for ( int j = 0; j < 11; j++ )
						cout << dynam.getStateValue(j,i,5,5) << "\t";
					cout << "\n";
				}
				cout << "\n";
			}	// End discount for
		}
        break;

		// EXERCISE 3: POLICY EVALUATION SMART
		case 5:{
			DynamicProgrammingSmart dynam;
			cout << "Iterations to evaluate all states' policy: "
									<< dynam.policyEvaluation(0.8, false) << "\n\n";
			cout << "Results: \n";
			cout << "Value of state (  0,  0 ) - (  5,  5 ) : "
									<< dynam.getStateValue( 0,  0,  5,  5) << "\n";
			cout << "Value of state (  2,  3 ) - (  5,  4 ) : "
									<< dynam.getStateValue( 2,  3,  5,  4) << "\n";
			cout << "Value of state (  2, 10 ) - ( 10,  0 ) : "
									<< dynam.getStateValue( 2, 10, 10,  0) << "\n";
			cout << "Value of state ( 10, 10 ) - (  0,  0 ) : "
									<< dynam.getStateValue(10, 10,  0,  0) << "\n";
		}
		break;

		// EXERCISE 3: VALUE ITERATION SMART
		case 6:{

			DynamicProgrammingSmart dynam;
            
			for ( double discountFactor=0.1; discountFactor<=0.9; discountFactor+=0.2 ) {
				cout << "For Discount Factor: " << discountFactor << "\n";
                cout << "Cycles of Value Iteration: " << dynam.valueIteration(discountFactor) << "\n";
                cout << "Results: \n\n";

                for ( int i = 0; i < 11; i++ ) {
                    for ( int j = 0; j < 11; j++ )
						cout << dynam.getStateValue(j,i,5,5) << "\t";
					cout << "\n";
				}
				cout << "\n";
			}	// End discount for
		}
		break;
		
		// EXERCISE 3: POLICY ITERATION SMART
		case 7:{
			DynamicProgrammingSmart dynam;

            for ( double discountFactor=0.1; discountFactor<=0.9; discountFactor+=0.2 ) {
				cout << "For Discount Factor: " << discountFactor << "\n";
                cout << "Cycles of Policy Iteration: " << dynam.policyIteration(discountFactor) << "\n";
                cout << "Results: \n\n";

				for ( int i = 10; i >= 0; i-- ) {
					for ( int j = 0; j < 11; j++ )
						cout << dynam.getStateValue(j,i,5,5) << "\t";
					cout << "\n";
				}
				cout << "\n";
			}	// End discount for
		}
		break;

		// EXIT PROGRAM
		case 0:
			cout << "Goodbye!\n\n\n";
			continue;

		default:
			cout << "Invalid selection, please enter one of the following:\n\n";
			continue;

        }	// Switch menuSelect

	timer = clock() - timer;
	cout << "\nThis operation took " << ((float)timer)/CLOCKS_PER_SEC << " seconds.\n\n\n";
    } while (menuSelect != 0);

	return 0;
}

